package com.ht.web.aduit;

import com.ht.bean.aduit.Holiday;
import com.ht.bean.emp.Dep;
import com.ht.bean.emp.Empinfo;
import com.ht.bean.json.JsonData;
import com.ht.bean.student.Studentfloor;
import com.ht.bean.student.Studenthuor;
import com.ht.service.aduit.HolidayService;
import com.ht.service.emp.DepService;
import com.ht.service.emp.EmpinfoService;
import com.ht.service.student.DeptService;
import com.ht.util.Contants;
import com.ht.util.Pager;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.FlowNode;
import org.activiti.bpmn.model.SequenceFlow;
import org.activiti.engine.*;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.history.HistoricVariableInstance;
import org.activiti.engine.impl.RepositoryServiceImpl;
import org.activiti.engine.impl.identity.Authentication;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Comment;
import org.activiti.engine.task.Task;
import org.activiti.image.ProcessDiagramGenerator;
import org.activiti.image.impl.DefaultProcessDiagramGenerator;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author 王钟华
 * @date 2020-06-19 19:21
 */
@RequestMapping("holiday")
@Controller
public class HolidayController {
    @Resource
    private JsonData jsonData;


    @Resource
    private ProcessEngine processEngine;
    @Resource
    private TaskService taskService;
    @Resource
    private RuntimeService runtimeService;
    @Resource
    private HistoryService historyService;
    @Resource
    private RepositoryService repositoryService;


    @Resource
    private DepService depService;
    @Resource
    private EmpinfoService empinfoService;


    @Resource
    private HolidayService holidayService;


    /**
     * @return
     * 去我的请假页面
     */
    @RequestMapping("list")
    public String list(){
        return "aduit/holidayList";
    }


    /**
     * @return
     * 去请假申请页面
     */
    @RequestMapping("toAdd")
    public String toAdd(){
        return "aduit/holidayAdd";
    }


    /**
     * @return
     * 添加请假申请
     */
    @RequestMapping("/add")
    @ResponseBody
    public Integer add(Holiday holiday,HttpSession session,String key) {
        Boolean index = false;//申请人是否为部门领导（默认不是）
        Integer empp = 0;//部门领导的id
        Integer emppp = 0;//总经理的id

        holiday.setStatus(Contants.HOLIDAY_START);//设置请假单的状态
        Empinfo empinfo = (Empinfo) session.getAttribute("user");//获取当前登录的用户，也就是申请人
        holiday.setEmpid(empinfo.getEmp_id());//


        Dep dep = depService.getDepByFid(empinfo.getDep_id());
        if (dep.getParentid() == 0){
            return 2;

        }else {
            //二级或三级
            Dep dep1 = depService.getDepByEmpid(empinfo.getEmp_id());
            System.out.println("dep1 = " + dep1);
            if (dep1 == null){
                dep1 = depService.getDepByFid(empinfo.getDep_id());
                empp = dep1.getChairman();
                Dep dep2 = depService.getDepByFid(dep1.getParentid());
                emppp = dep2.getChairman();
            }else{
                Dep dep2 =depService.getDepByFid(dep1.getParentid());
                emppp = dep2.getChairman();
                index = true;
            }
        }



        //设置流程变量（单据和流程实例绑定的中间变量）
        Map vars = new HashMap();
        vars.put("emp",holiday.getEmpid());//用户id
        vars.put("day",holiday.getHolidayday());//天数

        vars.put("empp",empp);
        vars.put("index",index);
        vars.put("emppp",emppp);
        Integer i = holidayService.insert(holiday);
        vars.put("holidayId",holiday.getHolidayid());//单据
        //根据流程定义的key来启动一个流程实例
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(key, String.valueOf(holiday.getHolidayid()),vars);
        System.out.println("流程实例ID： "+processInstance.getId());

        //通过流程实例ID获取到当前正在实行的任务(填写申请也是一个任务)
        Task task =  taskService.createTaskQuery().processInstanceId(processInstance.getId()).orderByProcessInstanceId().desc().singleResult();
        //完成这个任务
        taskService.complete(task.getId(),vars);

        return i;
    }

    //查看批注
    @RequestMapping("/lookComment")
    public String lookComment(int holidayId,Model model){
        try {
            //通过jobID查询历史变量对象
            HistoricVariableInstance hvi = historyService.createHistoricVariableInstanceQuery().variableValueEquals("holidayId", holidayId).singleResult();
            //根据流程实例ID查询历史备注集合



            List<Comment> commentList = taskService.getProcessInstanceComments(hvi.getProcessInstanceId());
            List<Holiday> holidayList = new ArrayList<>();
            for (Comment s: commentList) {
                Holiday holiday = new Holiday();
                Empinfo empinfo = empinfoService.selectByPrimaryKey(Integer.valueOf(s.getUserId()));
                holiday.setStarttime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(s.getTime()));
                holiday.setEmpName(empinfo.getEmp_name());
                holiday.setEmpid(Integer.valueOf(s.getId()));
                holidayList.add(holiday);

            }
            model.addAttribute("holidayList",holidayList);
        }catch (Exception e){
            List<Holiday> holidayList = new ArrayList<>();
            model.addAttribute("holidayList",holidayList);
        }
        return "aduit/holidayComment";
    }

    /*//查看我的任务*/
    @RequestMapping("/myTask")
    public String myTask(HttpSession session,Model model){

        Empinfo empinfo  = (Empinfo) session.getAttribute("user");
        List list1 = new ArrayList();
        //根据用户名称查找办理人是我的任务(act_ru_task)
        List<Task> list = taskService.createTaskQuery().taskAssignee(empinfo.getEmp_id().toString()).list();
        for (Task task:list) {
            Task task1=taskService.createTaskQuery().taskId(task.getId()).singleResult();
            String processInstans=task1.getProcessInstanceId();
            System.out.println("流程实例id"+processInstans);
            ProcessInstance result = runtimeService.createProcessInstanceQuery().processInstanceId(processInstans).singleResult();
            String businessKey = result.getBusinessKey();
            Holiday h = holidayService.selectByPrimaryKey(Integer.valueOf(businessKey));
            h.setEmpName(empinfoService.selectByPrimaryKey(h.getEmpid()).getEmp_name());
            h.setTask(task);
            list1.add(h);
        }
        model.addAttribute("List",list1);

        return "aduit/holidayMyTask";
    }




    /*//查看我的历史任务*/
    @RequestMapping("/myHistoryTask")
    public String myHistoryTask(HttpSession session,Map map){

        Empinfo empinfo  = (Empinfo) session.getAttribute("user");
        List list1 = new ArrayList();
        //根据act_hi_taskinst表查找是你的任务
        List<HistoricTaskInstance> list=processEngine.getHistoryService() // 历史任务Service
                .createHistoricTaskInstanceQuery() // 创建历史任务实例查询
                .taskAssignee(String.valueOf(empinfo.getEmp_id())) // 指定办理人
                .finished() // 查询已经完成的任务
                .list();


        for(HistoricTaskInstance hti:list){
            System.out.println("任务ID:"+hti.getId());
            System.out.println("流程实例ID:"+hti.getProcessInstanceId());
            System.out.println("任务名称："+hti.getName());
            System.out.println("办理人："+hti.getAssignee());
            System.out.println("开始时间："+hti.getStartTime());
            System.out.println("结束时间："+hti.getEndTime());
            System.out.println("=================================");

            list1.add(hti);
        }


        return "aduit/holidayMyHistoryTask";
    }






    @RequestMapping("data")
    @ResponseBody
    public JsonData data(@Param("limit")int limit , @Param("page")int page, HttpSession session){
        Pager pager = new Pager();
        pager.setPageSize(limit);
        pager.setCurrPage(page);

        Empinfo empinfo = (Empinfo) session.getAttribute("user");
        jsonData.setCount(holidayService.selCount());
        jsonData.setData(holidayService.sybase(pager,empinfo.getEmp_id()));
        return jsonData;
    }









    //完成审批
    @RequestMapping("/complete")
    public String complete(String taskId,String holidayid,String flow,String instId ,HttpSession session){
        //根据任务ID查询任务对象
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        //获取流程实例
        String processInstanceId = task.getProcessInstanceId();

        //通过单据ID获取单据对象
        Holiday holiday = holidayService.selectByPrimaryKey(Integer.valueOf(holidayid));

        //获取用户名称
        Empinfo empinfo = (Empinfo) session.getAttribute("user");
        String empId = empinfo.getEmp_id().toString();
        //设置任务办理人（主要是备注表使用）
        Authentication.setAuthenticatedUserId(empId);

        //给流程添加备注(任务ID，流程实例ID，备注信息)
        taskService.addComment(taskId,processInstanceId,"");

        //设置流程变量
        Map vars = new HashMap();
        vars.put("flow",flow);


        //完成当前任务
        taskService.complete(taskId,vars);

        //通过流程实例查询实例对象（如果实例对象为null表示流程结束）
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        if(processInstance==null){//表示流程结束了
            if(flow.equals("批准")){
                holiday.setStatus(Contants.HOLIDAY_OK);//已完成
            }else{
                holiday.setStatus(Contants.HOLIDAY_NOT);//未批准
            }

        }else {
            holiday.setStatus(Contants.HOLIDAY_LOADING);//审批中
        }
        holidayService.updateByPrimaryKey(holiday);
        return "redirect:/holiday/myTask";
    }



    @RequestMapping("/lookTaskImg")
    public String lookTaskImg(String holidayId, Model model, String instId,HttpServletResponse response) throws IOException {
//        image(response,instId);
        getActivitiProccessImage(instId,response);
        String processInstanceId = "";//流程实例ID
        if(holidayId!=null&&!"".equals(holidayId)){
            //通过单据id查找实例对象
            HistoricVariableInstance hvi = historyService.createHistoricVariableInstanceQuery().variableValueEquals("holidayId", Integer.parseInt(holidayId)).singleResult();
            //通过历史流程变量查询变量对象(获取流程实例ID)
            processInstanceId = hvi.getProcessInstanceId();
        }
        //我的任务（查看办理进度）
        if(instId!=null&&!"".equals(instId)){
            processInstanceId=instId;
        }
        //获取历史任务实例
        HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
                .processInstanceId(processInstanceId).singleResult();

        if(historicProcessInstance!=null){
            //获取流程定义信息
            ProcessDefinition pd = repositoryService.getProcessDefinition(historicProcessInstance.getProcessDefinitionId());
            // 获取流程定义的实体（包含了流程中的任务节点信息，连线信息）
            ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity)pd;
            // 获取流程历史中已执行节点，并按照节点在流程中执行先后顺序排序
            List<HistoricActivityInstance> historicActivityInstanceList = historyService.createHistoricActivityInstanceQuery()
                    .processInstanceId(processInstanceId).orderByHistoricActivityInstanceId().asc().list();
            // 已经激活的节点ID集合
            //激活的节点（1.任务已经完成；2.任务已经开始，但还未结束）
            List mapList = new ArrayList();
            //获取已经激活的节点ID
            for (HistoricActivityInstance activityInstance : historicActivityInstanceList) {
                mapList.add(activityInstance.getActivityId());
            }
            model.addAttribute("pd",pd);
            model.addAttribute("mapList",mapList);
            System.out.println("mapList = " + mapList);
            System.out.println("pd = " + pd);

            BpmnModel bpmnModel = repositoryService.getBpmnModel(historicProcessInstance.getProcessDefinitionId());
            // 已执行的线集合
            List<String> flowIds = new ArrayList<String>();
            // 获取流程走过的线 (getHighLightedFlows是下面的方法)
//            flowIds = getHighLightedFlows(bpmnModel,processDefinition, historicActivityInstanceList);


            // 获取流程图图像字符流
            ProcessDiagramGenerator pec = processEngine.getProcessEngineConfiguration().getProcessDiagramGenerator();
            //配置字体
            InputStream imageStream = pec.generateDiagram(bpmnModel, "png", mapList, flowIds,"宋体","微软雅黑","黑体",null,2.0);

            response.setContentType("image/png");
            OutputStream os = response.getOutputStream();
            int bytesRead = 0;
            byte[] buffer = new byte[8192];
            while ((bytesRead = imageStream.read(buffer, 0, 8192)) != -1) {
                os.write(buffer, 0, bytesRead);
            }
            os.flush();
            os.close();
        }
        return null;
    }













    /**
     * 获取流程图像，已执行节点和流程线高亮显示
     */

    public void getActivitiProccessImage(String processInstanceId, HttpServletResponse response)
    {
        //logger.info("[开始]-获取流程图图像");
        try {
            //  获取历史流程实例
            HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
                    .processInstanceId(processInstanceId).singleResult();

            if (historicProcessInstance == null) {
                //throw new BusinessException("获取流程实例ID[" + pProcessInstanceId + "]对应的历史流程实例失败！");
            }
            else
            {
                // 获取流程定义
                ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService)
                        .getDeployedProcessDefinition(historicProcessInstance.getProcessDefinitionId());

                // 获取流程历史中已执行节点，并按照节点在流程中执行先后顺序排序
                List<HistoricActivityInstance> historicActivityInstanceList = historyService.createHistoricActivityInstanceQuery()
                        .processInstanceId(processInstanceId).orderByHistoricActivityInstanceId().asc().list();

                // 已执行的节点ID集合
                List<String> executedActivityIdList = new ArrayList<String>();
                int index = 1;
                //logger.info("获取已经执行的节点ID");
                for (HistoricActivityInstance activityInstance : historicActivityInstanceList) {
                    executedActivityIdList.add(activityInstance.getActivityId());

                    //logger.info("第[" + index + "]个已执行节点=" + activityInstance.getActivityId() + " : " +activityInstance.getActivityName());
                    index++;
                }

                BpmnModel bpmnModel = repositoryService.getBpmnModel(historicProcessInstance.getProcessDefinitionId());

                // 已执行的线集合
                List<String> flowIds = new ArrayList<String>();
                // 获取流程走过的线 (getHighLightedFlows是下面的方法)
                flowIds = getHighLightedFlows(bpmnModel,processDefinition, historicActivityInstanceList);

                System.out.println("executedActivityIdList = " + executedActivityIdList);
                System.out.println("flowIds = " + flowIds);

                // 获取流程图图像字符流
                ProcessDiagramGenerator pec = processEngine.getProcessEngineConfiguration().getProcessDiagramGenerator();
                //配置字体
                InputStream imageStream = pec.generateDiagram(bpmnModel, "png", executedActivityIdList, flowIds,"宋体","微软雅黑","黑体",null,2.0);

                response.setContentType("image/png");
                OutputStream os = response.getOutputStream();
                int bytesRead = 0;
                byte[] buffer = new byte[8192];
                while ((bytesRead = imageStream.read(buffer, 0, 8192)) != -1) {
                    os.write(buffer, 0, bytesRead);
                }
                os.close();
                imageStream.close();
            }
            //logger.info("[完成]-获取流程图图像");
        } catch (Exception e) {
            System.out.println(e.getMessage());
            //logger.error("【异常】-获取流程图失败！" + e.getMessage());
            //throw new BusinessException("获取流程图失败！" + e.getMessage());
        }
    }

    public List<String> getHighLightedFlows(BpmnModel bpmnModel,ProcessDefinitionEntity processDefinitionEntity,List<HistoricActivityInstance> historicActivityInstances)
    {
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //24小时制
        List<String> highFlows = new ArrayList<String>();// 用以保存高亮的线flowId

        for (int i = 0; i < historicActivityInstances.size() - 1; i++)
        {
            // 对历史流程节点进行遍历
            // 得到节点定义的详细信息
            FlowNode activityImpl = (FlowNode)bpmnModel.getMainProcess().getFlowElement(historicActivityInstances.get(i).getActivityId());


            List<FlowNode> sameStartTimeNodes = new ArrayList<FlowNode>();// 用以保存后续开始时间相同的节点
            FlowNode sameActivityImpl1 = null;

            HistoricActivityInstance activityImpl_ = historicActivityInstances.get(i);// 第一个节点
            HistoricActivityInstance activityImp2_ ;

            for(int k = i + 1 ; k <= historicActivityInstances.size() - 1; k++)
            {
                activityImp2_ = historicActivityInstances.get(k);// 后续第1个节点

                if ( activityImpl_.getActivityType().equals("userTask") && activityImp2_.getActivityType().equals("userTask") &&
                        df.format(activityImpl_.getStartTime()).equals(df.format(activityImp2_.getStartTime()))   ) //都是usertask，且主节点与后续节点的开始时间相同，说明不是真实的后继节点
                {

                }
                else
                {
                    sameActivityImpl1 = (FlowNode)bpmnModel.getMainProcess().getFlowElement(historicActivityInstances.get(k).getActivityId());//找到紧跟在后面的一个节点
                    break;
                }

            }
            sameStartTimeNodes.add(sameActivityImpl1); // 将后面第一个节点放在时间相同节点的集合里
            for (int j = i + 1; j < historicActivityInstances.size() - 1; j++)
            {
                HistoricActivityInstance activityImpl1 = historicActivityInstances.get(j);// 后续第一个节点
                HistoricActivityInstance activityImpl2 = historicActivityInstances.get(j + 1);// 后续第二个节点

                if (df.format(activityImpl1.getStartTime()).equals(df.format(activityImpl2.getStartTime()))  )
                {// 如果第一个节点和第二个节点开始时间相同保存
                    FlowNode sameActivityImpl2 = (FlowNode)bpmnModel.getMainProcess().getFlowElement(activityImpl2.getActivityId());
                    sameStartTimeNodes.add(sameActivityImpl2);
                }
                else
                {// 有不相同跳出循环
                    break;
                }
            }
            List<SequenceFlow> pvmTransitions = activityImpl.getOutgoingFlows() ; // 取出节点的所有出去的线

            for (SequenceFlow pvmTransition : pvmTransitions)
            {// 对所有的线进行遍历
                FlowNode pvmActivityImpl = (FlowNode)bpmnModel.getMainProcess().getFlowElement( pvmTransition.getTargetRef());// 如果取出的线的目标节点存在时间相同的节点里，保存该线的id，进行高亮显示
                if (sameStartTimeNodes.contains(pvmActivityImpl)) {
                    highFlows.add(pvmTransition.getId());
                }
            }

        }
        return highFlows;

    }






    public void image(HttpServletResponse response,String processInstanceId) {
        try {
            InputStream is = getDiagram(processInstanceId);
            if (is == null)
                return;

            response.setContentType("image/png");

            BufferedImage image = ImageIO.read(is);
            OutputStream out = response.getOutputStream();
            ImageIO.write(image, "png", out);

            is.close();
            out.close();
        } catch (Exception ex) {
        }
    }


    public InputStream getDiagram(String processInstanceId) {
        //获得流程实例
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                .processInstanceId(processInstanceId).singleResult();
        String processDefinitionId = StringUtils.EMPTY;
        if (processInstance == null) {
            //查询已经结束的流程实例
            HistoricProcessInstance processInstanceHistory =
                    historyService.createHistoricProcessInstanceQuery()
                            .processInstanceId(processInstanceId).singleResult();
            if (processInstanceHistory == null)
                return null;
            else
                processDefinitionId = processInstanceHistory.getProcessDefinitionId();
        } else {
            processDefinitionId = processInstance.getProcessDefinitionId();
        }

        //使用宋体
        String fontName = "宋体";
        //获取BPMN模型对象
        BpmnModel model = repositoryService.getBpmnModel(processDefinitionId);
        //获取流程实例当前的节点，需要高亮显示
        List<String> currentActs = Collections.EMPTY_LIST;
        if (processInstance != null)
            currentActs = runtimeService.getActiveActivityIds(processInstance.getId());

        return processEngine.getProcessEngineConfiguration()
                .getProcessDiagramGenerator()
                .generateDiagram(model, "png", currentActs, new ArrayList<String>(),
                        fontName, fontName, fontName, null, 1.0);
    }


}
